package com.chenfengyao.gamereversi.core

import android.util.Log
import com.chenfengyao.gamereversi.common.CELL_COUNT
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow

/**
 * Created by ChenFengYao on 2021/6/3
 *
 * 翻转棋裁判类
 */
class Referee {
    val board = Array(CELL_COUNT) { Array(CELL_COUNT) { ChessPiece.NONE } }

    private val _boardFlow = MutableSharedFlow<Array<Array<ChessPiece>>>(replay = 1)
    val boardFlow = _boardFlow.asSharedFlow()

    private val _nextPlayerFlow = MutableStateFlow(ChessPiece.BLACK)
    val nextPlayerFlow = _nextPlayerFlow.asStateFlow()
    val nextPlayer: ChessPiece
        get() = _nextPlayerFlow.value

    // 记录黑白棋的数量
    private val _scoreFlow = MutableStateFlow(intArrayOf(2, 2))
    val scoreFlow = _scoreFlow.asStateFlow()

    private val _gameOverFlow = MutableStateFlow(false)
    val gameOverFlow = _gameOverFlow.asStateFlow()

    // 8个方向
    private val directions = arrayOf(
        intArrayOf(-1, -1), intArrayOf(-1, 0), intArrayOf(-1, 1),
        intArrayOf(0, -1), intArrayOf(0, 1),
        intArrayOf(1, -1), intArrayOf(1, 0), intArrayOf(1, 1)
    )

    /**
     * 初始化棋盘
     */
    fun init() {
        _nextPlayerFlow.value = ChessPiece.BLACK

        for (i in 0 until CELL_COUNT) {
            for (j in 0 until CELL_COUNT) {
                board[i][j] = ChessPiece.NONE
            }
        }

        board[CELL_COUNT / 2 - 1][CELL_COUNT / 2 - 1] = ChessPiece.WHITE
        board[CELL_COUNT / 2][CELL_COUNT / 2] = ChessPiece.WHITE
        board[CELL_COUNT / 2 - 1][CELL_COUNT / 2] = ChessPiece.BLACK
        board[CELL_COUNT / 2][CELL_COUNT / 2 - 1] = ChessPiece.BLACK

        updateBoard()
    }


    /**
     * 判断是否可以在指定位置放置棋子
     * 规则:
     *  1. 该位置必须为空
     *  2. 下了该棋子后，至少有一个方向可以翻转对方的棋子
     */
    fun canPlace(x: Int, y: Int, targetPlayer: ChessPiece = nextPlayer): Boolean {
        Log.d("Referee", "canPlace: x=$x, y=$y")
        // 该位置必须为空
        if (board[x][y] != ChessPiece.NONE) {
            return false
        }

        // 下了该棋子后，至少有一个方向可以翻转对方的棋子
        val opponent = if (targetPlayer == ChessPiece.BLACK) ChessPiece.WHITE else ChessPiece.BLACK

        for (direction in directions) {
            var count = 0
            val dx = direction[0]
            val dy = direction[1]
            var tx = x + dx
            var ty = y + dy
            while (tx in 0 until CELL_COUNT && ty in 0 until CELL_COUNT) {
                if (board[tx][ty] == ChessPiece.NONE) {
                    break
                }
                if (board[tx][ty] == opponent) {
                    count++
                } else {
                    if (count > 0) {
                        return true
                    }
                    break
                }
                tx += dx
                ty += dy
            }
        }

        return false
    }

    fun onCellClick(x: Int, y: Int) {
        if (!canPlace(x, y)) {
            return
        }

        val opponent = if (nextPlayer == ChessPiece.BLACK) ChessPiece.WHITE else ChessPiece.BLACK
        // 下了该棋子后，至少有一个方向可以翻转对方的棋子
        for (direction in directions) {
            var count = 0
            var dx = direction[0]
            var dy = direction[1]
            var tx = x + dx
            var ty = y + dy
            while (tx in 0 until CELL_COUNT && ty in 0 until CELL_COUNT) {
                if (board[tx][ty] == ChessPiece.NONE) {
                    break
                }
                if (board[tx][ty] == opponent) {
                    count++
                } else {
                    if (count > 0) {
                        var tx2 = x + dx
                        var ty2 = y + dy
                        while (tx2 != tx || ty2 != ty) {
                            board[tx2][ty2] = nextPlayer
                            tx2 += dx
                            ty2 += dy
                        }
                        break
                    }
                    break
                }
                tx += dx
                ty += dy
            }
        }

        board[x][y] = nextPlayer
        updateBoard()
        if (!changePlayer()) {
            checkGameOver()
        }
    }

    /**
     * 判断游戏是否结束
     */
    private fun checkGameOver() {
        _gameOverFlow.value = !hasPlace(ChessPiece.BLACK) && !hasPlace(ChessPiece.WHITE)
    }

    /**
     * 切换玩家
     * 黑白棋交替,如果交换后没有可以下的位置,则继续交换
     */
    private fun changePlayer(): Boolean {
        val current = nextPlayer
        _nextPlayerFlow.value = ChessPiece.NONE
        val changePlayer =
            if (current == ChessPiece.BLACK) ChessPiece.WHITE else ChessPiece.BLACK

        if (!hasPlace(changePlayer)) {
            _nextPlayerFlow.value = current
            return false
        }
        _nextPlayerFlow.value = changePlayer

        return true
    }

    /**
     * 判断是否有可以下的位置
     */
    private fun hasPlace(piece: ChessPiece): Boolean {
        for (i in 0 until CELL_COUNT) {
            for (j in 0 until CELL_COUNT) {
                if (canPlace(i, j, piece)) {
                    return true
                }
            }
        }
        return false
    }

    /**
     * 计算黑白棋的数量
     */
    fun calculateScore() {
        val score = intArrayOf(0, 0)
        for (i in 0 until CELL_COUNT) {
            for (j in 0 until CELL_COUNT) {
                if (board[i][j] == ChessPiece.BLACK) {
                    score[0]++
                } else if (board[i][j] == ChessPiece.WHITE) {
                    score[1]++
                }
            }
        }
        _scoreFlow.value = score
    }

    private fun updateBoard() {
        _boardFlow.tryEmit(board)
        calculateScore()    // 计算黑白棋的数量
    }
}